import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.Semaphore;

import javax.swing.JOptionPane;

import com.nullprogram.chess.Board;
import com.nullprogram.chess.Game;
import com.nullprogram.chess.GameEvent;
import com.nullprogram.chess.GameListener;
import com.nullprogram.chess.Piece;
import com.nullprogram.chess.ai.AlphaBeta;
import com.nullprogram.chess.ai.Minimax;
import com.nullprogram.chess.boards.StandardBoard;
import com.nullprogram.chess.pieces.Bishop;
import com.nullprogram.chess.pieces.King;
import com.nullprogram.chess.pieces.Knight;
import com.nullprogram.chess.pieces.Pawn;
import com.nullprogram.chess.pieces.Queen;
import com.nullprogram.chess.pieces.Rook;

public class ExperimentDriver implements GameListener {

	int numGames;
	AlphaBeta p1;
	AlphaBeta p2;
	HashMap<Class, Double> pv1;
	HashMap<Class, Double> pv2;
	String fileData = "Pawn,Knight,Bishop,Rook,Queen,King\n";
	FileWriter fstream = null;
	BufferedWriter out = null;

	int i;
	final static int DEPTH = 4;
	final static int NUM_GAMES = 500;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ExperimentDriver e = new ExperimentDriver();

		e.numGames = NUM_GAMES;
		try {
			e.runExperiment(DEPTH);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}

	}

	public void runExperiment(int depth) throws InterruptedException {
		StandardBoard sb = new StandardBoard();
		Game g = new Game(sb);
		AlphaBeta ab = new AlphaBeta(g);
		pv1 = ab.getPieceValues();

		AlphaBeta ab2 = new AlphaBeta(g);
		pv2 = ab.getPieceValues();
		

		try {
			fstream = new FileWriter("experimentData.csv");
			out = new BufferedWriter(fstream);
			out.write(fileData);
		} catch (IOException e) {
			e.printStackTrace();
		}
		

		for (i = 0; i < numGames; i++) {
			System.out.println("Game " + i);
			printPieceValues(pv1);
			StandardBoard board = new StandardBoard();
			Game game = new Game(board);
			p1 = new AlphaBeta(game);
			p1.setMaxDepth(depth);
			p1.setPieceValues(pv1);
			p2 = new AlphaBeta(game);
			p2.setMaxDepth(depth);
			p2.setTD(false);
			p2.setPieceValues(pv2);
			game.seat(p1, p2);
			game.addGameListener(this);
			game.begin();
			Date start = new Date();
			Thread.sleep(1000);
			while (!game.isDone()) {
				// limit game time
				if (new Date().getTime() - start.getTime() > 15000) {
					game.end();
				}
				Thread.sleep(1000);
			}
			printPieceValues(pv1);
			System.out.println("\n\n");
		}
		try {
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	final double alpha_mod = .997;
	double alpha = .05;
	final double lamda = .98;

	@Override
	public void gameEvent(GameEvent e) {
		if (e.getGame().isDone()) {
			// TD Learn
			ArrayList<Double> P = p1.getP();
			ArrayList<HashMap<String, Double>> wPk = p1.getWPK();

			Iterator i = pv1.keySet().iterator();

			while (i.hasNext()) {
				Class c = (Class) i.next();
				if (wPk.get(0).get(c.getSimpleName()) != null) {

					String pieceName = c.getSimpleName();
					for (int t = 0; t < P.size() - 2; t++) {
						double sum = 0;
						for (int k = 0; k < t; k++) {
							sum += Math.pow(lamda, t - k)
									* wPk.get(k).get(pieceName);
						}
							
						// original
						double deltaW = alpha * (P.get(t + 1) - P.get(t)) * sum;
						//double deltaW = alpha * (P.get(t + 1) - P.get(t)) * wPk.get(t).get(pieceName);
						


						// System.out.println("Sum: "+sum);
						// String formatDeltaW = String.format("%.16f", deltaW);
						//System.out.println("Delta "+c.getSimpleName()+": "+String.format("%.16f",deltaW));

						pv1.put(c, pv1.get(c) + deltaW); 
					}
				}
			}
			
			try {
				out.write(pv1.get(Pawn.class)+","+pv1.get(Knight.class)+","+pv1.get(Bishop.class)
						+","+pv1.get(Rook.class)+","+pv1.get(Queen.class)+","+pv1.get(King.class)+"\n");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			
			

			if(alpha > .001)
				alpha = alpha * alpha_mod;
		}

	}

	public void printPieceValues(HashMap<Class, Double> pieceValues) {
		Iterator<Class> i = pieceValues.keySet().iterator();
		while (i.hasNext()) {
			Class c = (Class) i.next();
			System.out.println(c.getSimpleName() + " value: "
					+ String.format("%.16f", pieceValues.get(c)));
		}
	}

}
